package net.cloudcodex.client.storyboard.handler;

import java.util.Date;
import java.util.List;

import net.cloudcodex.client.util.rpc.SuccessCallback;
import net.cloudcodex.shared.dto.Result;
import net.cloudcodex.shared.dto.msg.SceneDTO;
import net.cloudcodex.shared.rpc.CampaignRPC;
import net.cloudcodex.shared.rpc.CampaignRPCAsync;

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * Server-side {@link SceneDTO} checking {@link Timer}.
 * 
 * @author ADaroussin
 */
public class SceneTimer extends Timer {
	/**
	 * Server-side scene check delays: 10sec, 20sec, 40sec, 1min, 2mins, 3mins,
	 * 5mins (max).
	 */
	private static final int[] DELAYS = new int[] { 5000 };

	private final CampaignRPCAsync service;
	private final long campaignId;
	private final long characterId;
	private final AsyncCallback<List<SceneDTO>> sceneCallback;

	private final SuccessCallback<Result<List<SceneDTO>>> timerCallback;

	private int delayIndex = -1;
	private Date lastTime = null;
	private boolean isStoped = false;

	public SceneTimer(CampaignRPCAsync service, long campaignId, long characterId,
			AsyncCallback<List<SceneDTO>> callback) {
		this.service = service;
		this.campaignId = campaignId;
		this.characterId = characterId;
		this.sceneCallback = callback;

		this.timerCallback = new SuccessCallback<Result<List<SceneDTO>>>() {
			@Override
			public void onSuccess(Result<List<SceneDTO>> result) {
				if (isStoped) {
					return;
				}
				lastTime = result.getTimestamp();
				final List<SceneDTO> data = result.getData();
				final boolean isEmpty = (data == null ? true : data.isEmpty());
				if (!isEmpty) {
					// There is result: reset the delay and send the result
					delayIndex = -1;
					sceneCallback.onSuccess(data);
				}
				schedule();
			}
		};

		// First run now!
		this.run();
	}

	/**
	 * Call server-side service {@link CampaignRPC#getMessages}.
	 */
	@Override
	public void run() {
		service.getMessages(campaignId, characterId, null, lastTime, timerCallback);
	}

	/**
	 * Stop calling server-side service and treating further response
	 */
	public void stop() {
		isStoped = true;
		this.cancel();
	}
	
	/**
	 * Reset the delay and run now
	 */
	public void reset() {
		delayIndex = -1;
		this.run();
	}

	/**
	 * Schedule next {@link #run} according the current delay
	 */
	private void schedule() {
		if (delayIndex < DELAYS.length - 1) {
			delayIndex++;
		}
		this.schedule(DELAYS[delayIndex]);
	}
}
